package design.pattern.Lu18MementoPattern;

import lombok.Data;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @program JavaBase
 * @description: 备忘录模式
 *  最佳代码
 * @author: zhanglu
 * @create: 2020-04-26 13:58:00
 */
public class MementoPattern05 {

    public static void main(String[] args) {

        Originator05 originator05 = new Originator05();
        Caretaker05 caretaker05 = new Caretaker05();

        originator05.setState01("1");
        originator05.setState02("2");
        originator05.setState03("3");

        originator05.toString();

        IMemento05 memento = originator05.createMemento();
        caretaker05.setMemento05(memento);

        originator05.setState01("4");
        originator05.setState02("5");
        originator05.setState03("6");

        originator05.toString();

        originator05.restoreMemento(caretaker05.getMemento05());

        originator05.toString();

    }

}

@Data
class Originator05{

    private String state01;
    private String state02;
    private String state03;

    public IMemento05 createMemento(){
        Memento05 memento05 = new Memento05();
        memento05.setKvs(BeanUtils05.readValue(this));
        return memento05;
    }

    public void restoreMemento(IMemento05 memento05){
        BeanUtils05.writeValue(this, ((Memento05) memento05).getKvs());
    }

    @Data
    private class Memento05 implements IMemento05{
        private Map<String, Object> kvs = new HashMap<>();
    }

    public String toString() {
        System.out.println("Originator05{" +
                "state01='" + state01 + '\'' +
                ", state02='" + state02 + '\'' +
                ", state03='" + state03 + '\'' +
                '}');
        return null;
    }
}

interface IMemento05{

}

@Data
class Caretaker05{
    private IMemento05 memento05;
}

class BeanUtils05{

    public static Map<String, Object> readValue(Object obj){
        Map<String, Object> res = new HashMap<>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor descriptor : propertyDescriptors) {
                String fieldName = descriptor.getName();
                Method readMethod = descriptor.getReadMethod();
                if(!fieldName.equalsIgnoreCase("class")){
                    Object fieldValue = readMethod.invoke(obj, new Object[]{});
                    res.put(fieldName, fieldValue);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

    public static void writeValue(Object obj, Map<String, Object> res){
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                String fieldName = propertyDescriptor.getName();
                if(res.containsKey(fieldName)){
                    Method writeMethod = propertyDescriptor.getWriteMethod();
                    writeMethod.invoke(obj, new Object[]{res.get(fieldName)});
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}


